#include "tetris.h"
#include "ui_tetris.h"
#include<time.h>
#include<QMessageBox>
#include<QDebug>
#include<QPainter>
#include<QKeyEvent>

Tetris::Tetris(QWidget *parent):
    QMainWindow(parent),
    ui(new Ui::Tetris)
{
    ui->setupUi(this);
    this->setGeometry(QRect(500,150,520,820));
    //调整窗口尺寸布局；
    resize(AREA_COL*BLOCK_SIZE+MARGIN*4+4*BLOCK_SIZE,AREA_ROW*BLOCK_SIZE+MARGIN*2);
    this->setWindowTitle("俄罗斯方块");
    //初始化游戏
    InitGame();
}

Tetris::~Tetris()
{
    delete ui;
}

void Tetris::paintEvent(QPaintEvent* event)
{
    //update()或程序第一次启动时自动执行，用于画图
    QPainter painter(this);

    //画游戏背景
    //外墙
    painter.setPen(Qt::black);
    painter.setBrush(Qt::blue);
    painter.drawRect(15,35,490,730);
    //内墙
    painter.setPen(Qt::black);
    painter.setBrush(Qt::green);
    painter.drawRect(20,40,480,720);
    //画格子
    painter.setPen(Qt::yellow);
    for(int i=0;i<=24;i++)//画横线
    {
         painter.drawLine(20,i*30+40,500,i*30+40);
    }
    for(int i=0;i<=16;i++)
    {
        painter.drawLine(i*30+20,40,i*30+20,760);
    }

    //绘制下落方块和稳定方块，注意方块边线的边线的颜色是根据setPen来的，默认黑色
    for(int i=0;i<AREA_ROW;i++)
    {
        for(int j=0;j<AREA_COL;j++)
        {
            //绘制活动方块
            if(game_area[i][j]==1)
            {
                painter.setBrush(QBrush(Qt::red,Qt::SolidPattern));
                painter.drawRect(j*BLOCK_SIZE+MARGIN,i*BLOCK_SIZE+MARGIN+20,BLOCK_SIZE,BLOCK_SIZE);
            }
            //绘制稳定方块
            if(game_area[i][j]==2)
            {
                painter.setBrush(QBrush(Qt::black,Qt::SolidPattern));
                painter.drawRect(j*BLOCK_SIZE+MARGIN,i*BLOCK_SIZE+MARGIN+20,BLOCK_SIZE,BLOCK_SIZE);
            }
        }
    }

   ///绘制方块预告
    painter.setBrush(QBrush(Qt::blue,Qt::SolidPattern));
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
            if(next_block[i][j]==1)
            {
                painter.drawRect(MARGIN*3+AREA_COL*BLOCK_SIZE+j*BLOCK_SIZE,MARGIN+i*BLOCK_SIZE+60,BLOCK_SIZE,BLOCK_SIZE);
            }
        }
    }

    //绘制分数
    painter.setPen(Qt::black);
    painter.setFont(QFont("Arial",15));
    painter.drawText(MARGIN*2+AREA_COL*BLOCK_SIZE,MARGIN*2+4*BLOCK_SIZE+70,tr("分数："));
    painter.drawText(MARGIN*2+AREA_COL*BLOCK_SIZE+80,MARGIN*2+4*BLOCK_SIZE+70,QString::number(score));

}
//定义图案代码和边界
//田字
int item1[4][4]=
{
    {0,0,0,0},
    {0,1,1,0},
    {0,1,1,0},
    {0,0,0,0}
};
//右L
int item2[4][4]=
{
    {0,1,0,0},
    {0,1,0,0},
    {0,1,1,0},
    {0,0,0,0}
};
//右L
int item3[4][4]=
{
    {0,0,1,0},
    {0,0,1,0},
    {0,1,1,0},
    {0,0,0,0}
};
//右S
int item4[4][4]=
{
    {0,1,0,0},
    {0,1,1,0},
    {0,0,1,0},
    {0,0,0,0}
};
//左S
int item5[4][4]=
{
    {0,0,1,0},
    {0,1,1,0},
    {0,1,0,0},
    {0,0,0,0}
};
//山
int item6[4][4]=
{
    {0,0,0,0},
    {0,0,1,0},
    {0,1,1,1},
    {0,0,0,0}
};
//I
int item7[4][4]=
{
    {0,0,1,0},
    {0,0,1,0},
    {0,0,1,0},
    {0,0,1,0}
};

//拷贝方块图案
inline void block_cpy(int dbound[4][4], int sbound[4][4])
{
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
            dbound[i][j]=sbound[i][j];
        }
    }
}

void Tetris::InitGame()
{
    InitMenu();
    //开始的时候所有的位置均为空
   for(int i=0;i<AREA_ROW;i++)
      {
         for(int j=0;j<AREA_COL;j++)
            {
               game_area[i][j]=0;
            }
      }

   speed_ms=800;
   refresh_ms=30;

   //初始化随机种子
   srand(time(0));

   //分数置零
   score=0;

   //开始游戏
   StartGame();
}

void Tetris::InitMenu()
{
    menu=new QMenu(this);
    menu->setTitle(tr("游戏"));

    helpMenu=new QMenu();
    helpMenu->setTitle(tr("帮助"));

    startGameAction=new QAction(this);
    startGameAction->setText(tr("开始游戏"));
    menu->addAction(startGameAction);

    pauseOrcontinueGameAction=new QAction(this);
    pauseOrcontinueGameAction->setText("暂停游戏");
    menu->addAction(pauseOrcontinueGameAction);

    stopGameAction=new QAction(this);
    stopGameAction->setText("结束游戏");
    menu->addAction(stopGameAction);

    helpAction=new QAction(this);
    helpAction->setText("操作指南");
    helpMenu->addAction(helpAction);

    //添加到菜单栏
    menuBar()->addMenu(menu);
    menuBar()->addMenu(helpMenu);

    //事件绑定
    connect(startGameAction,SIGNAL(triggered()),this,SLOT(slotStartGame()));
    connect(pauseOrcontinueGameAction,SIGNAL(triggered()),this,SLOT(slotPauseGame()));
    connect(stopGameAction,SIGNAL(triggered()),this,SLOT(slotStopGame()));
    connect(helpAction,SIGNAL(triggered()),this,SLOT(slotHelp()));
}

void Tetris::BlockRotate(int block[4][4])
{
    int temp_block[4][4];
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
            temp_block[3-j][i]=block[i][j];
        }
    }
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
            block[i][j]=temp_block[i][j];
        }
    }
}

void Tetris::CreatBlock(int block[4][4],int block_id)
{
   switch(block_id)
   {
   case 0:
       block_cpy(block,item1);
       break;
   case 1:
       block_cpy(block,item2);
       break;
   case 2:
       block_cpy(block,item3);
       break;
   case 3:
       block_cpy(block,item4);
       break;
   case 4:
       block_cpy(block,item5);
       break;
   case 5:
       block_cpy(block,item6);
       break;
   case 6:
       block_cpy(block,item7);
       break;
   default:
       break;
   }
}

void Tetris::GetBorder(int block[4][4],Border &border)
{
    int i=0,j=0;
    //计算上下左右边界
    //上边界
    for(i=3;i>=0;i--)
    {
        for(j=0;j<4;j++)
        {
            if(block[i][j]==1)
            {
                border.ubound=i;
                break;
            }
        }
    }
    //下边界
    for(i=0;i<4;i++)
    {
        for(j=0;j<4;j++)
        {
            if(block[i][j]==1)
            {
                border.dbound=i;
                break;
            }
        }
    }
    //左边界
    for(j=3;j>=0;j--)
    {
        for(i=0;i<4;i++)
        {
            if(block[i][j]==1)
            {
                border.lbound=j;
                break;
            }
        }
    }
    //右边界
    for(j=0;j<4;j++)
    {
        for(i=0;i<4;i++)
        {
            if(block[i][j]==1)
            {
                border.rbound=j;
                break;
            }
        }
    }
}

void Tetris::ResetBlock()
{
    //产生当前方块
    block_cpy(cur_block,next_block);
    GetBorder(cur_block,cur_border);

    //产生下一个方块
    int block_id=rand()%7;
    CreatBlock(next_block,block_id);

    //设置初始坐标，以方块左上角为锚点
    block_point start_point;
    start_point.pos_x=AREA_COL/2-2;
    start_point.pos_y=0;
    block_pos=start_point;
}

void Tetris::StartGame()
{
    gameStatus=GameStatus::RUNNING;
    game_timer=startTimer(speed_ms);//开启游戏timer
    paint_timer=startTimer(refresh_ms);
    //产生初始下一个方块
    int block_id=rand()%7;
    CreatBlock(next_block,block_id);
    ResetBlock();//产生方块
}

void Tetris::PauseOrContinueGame()
{
    if(gameStatus==GameStatus::RUNNING)
    {
        gameStatus=GameStatus::PAUSE;
        //游戏结束停止定时器

        killTimer(game_timer);
        killTimer(paint_timer);
        pauseOrcontinueGameAction->setText("继续游戏");
    }
    else
    {
        gameStatus=GameStatus::RUNNING;
        game_timer=startTimer(speed_ms);
        paint_timer=startTimer(refresh_ms);
        //产生初始化下一个方块
        int block_id=rand()%7;
        CreatBlock(next_block,block_id);
        ResetBlock();
        pauseOrcontinueGameAction->setText("暂停游戏");
    }
}

void Tetris::GameOver()
{
    gameStatus=GameStatus::STOP;
    //游戏结束停止计时器
    killTimer(game_timer);
    killTimer(paint_timer);
    QMessageBox::information(this,"failed","game over");
}


void Tetris::ConvertStable(int x,int y)
{
    for(int i=cur_border.ubound;i<=cur_border.dbound;i++)
    {
        for(int j=cur_border.lbound;j<=cur_border.rbound;j++)
        {
            if(cur_block[i][j]==1)
                game_area[y+i][x+j]=2;
        }
    }
}

void Tetris::BlockMove(Direction dir)
{
    switch(dir)
    {
    case UP:
        if(IsCollide(block_pos.pos_x,block_pos.pos_y,UP))
            break;
        //逆时针旋转90°
        BlockRotate(cur_block);
                //i和j从0到4重新设置方块
        for(int i=0;i<4;i++)
           {
            for(int j=0;j<4;j++)
               {
                        game_area[block_pos.pos_y+i][block_pos.pos_x+j]=cur_block[i][j];
               }
            }
        //重新计算边界
        GetBorder(cur_block,cur_border);
        break;
    case DOWN:
        //方块到达边界则不再移动
        if(block_pos.pos_y+cur_border.dbound==AREA_ROW-1)
        {
            //只有最终不能下落才能转成稳定方块
            ConvertStable(block_pos.pos_x,block_pos.pos_y);
            ResetBlock();
            break;
        }
        //碰撞检测，只计算上下左右边界，先尝试走一格，如果碰撞则稳定方块后跳出
        if(IsCollide(block_pos.pos_x,block_pos.pos_y,DOWN))
        {
            //只有最终不能下落才转成稳定方块
            ConvertStable(block_pos.pos_x,block_pos.pos_y);
            ResetBlock();
            break;
        }
        //恢复方块上场景，为了清除移动过程中的方块残留
        for(int j=cur_border.lbound;j<=cur_border.rbound;j++)
        {
            game_area[block_pos.pos_y][block_pos.pos_x+j]=0;
            game_area[block_pos.pos_y][block_pos.pos_x+j-1]=0;
        }
            //没有碰撞则下落一格
            block_pos.pos_y+=1;
            //方块下降一格，拷贝到场景
            for(int i=0;i<4;i++)
            {
                for(int j=cur_border.lbound;j<=cur_border.rbound;j++)
                {
                    if(block_pos.pos_y+i<=AREA_ROW-1&&game_area[block_pos.pos_y+i][block_pos.pos_x+j]!=2)
                    {
                        game_area[block_pos.pos_y+i][block_pos.pos_x+j]=cur_block[i][j];
                    }
                }
            }
          GetBorder(cur_block,cur_border);
        break;
    case LEFT:
        //到左边界或者碰撞不再向左
        if(block_pos.pos_x+cur_border.lbound==0||IsCollide(block_pos.pos_x,block_pos.pos_y,LEFT))
            break;
            //恢复方块右场景，为了清除方块残留
        for(int i=cur_border.ubound;i<=cur_border.dbound;i++)
        {
            game_area[block_pos.pos_y+i][block_pos.pos_x+3]=0;
        }
        block_pos.pos_x-=1;
        //方块左移一格，拷贝到场景
        for(int i=cur_border.ubound;i<=cur_border.dbound;i++)
        {
            for(int j=0;j<4;j++)
            {
                if(block_pos.pos_x+j>=0&&game_area[block_pos.pos_y+i][block_pos.pos_x+j]!=2)
                    game_area[block_pos.pos_y+i][block_pos.pos_x+j]=cur_block[i][j];
            }
        }
        break;
     case RIGHT:
        if(block_pos.pos_x+cur_border.rbound==AREA_COL-1||IsCollide(block_pos.pos_x,block_pos.pos_y,RIGHT))
            break;
        //为了清除方块残留
        for(int i=cur_border.ubound;i<=cur_border.dbound;i++)
        {
            game_area[block_pos.pos_y+i][block_pos.pos_x]=0;
        }
        block_pos.pos_x+=1;
        //方块左移一格，拷贝到场景
        for(int i=cur_border.ubound;i<=cur_border.dbound;i++)
        {
            for(int j=0;j<4;j++)
            {
                if(block_pos.pos_x+j<=AREA_COL-1&&game_area[block_pos.pos_y+i][block_pos.pos_x+j]!=2)
                    game_area[block_pos.pos_y+i][block_pos.pos_x+j]=cur_block[i][j];
            }
        }
        break;
    case SPACE:
        //一次到底
        //一个一个格下移，直到不能下移
        while(block_pos.pos_y+cur_border.dbound<AREA_ROW-1&&!IsCollide(block_pos.pos_x,block_pos.pos_y,DOWN))
        {
            //恢复方块上场景，为了清除移动过程中的方块残留
            for(int j=cur_border.lbound;j<=cur_border.rbound;j++)
            {
                game_area[block_pos.pos_y][block_pos.pos_x+j]=0;
            }
                //没有碰撞则下落一格
                block_pos.pos_y+=1;
                //方块下降一格，拷贝到场景
                for(int i=0;i<4;i++)
                {
                    for(int j=cur_border.lbound;j<=cur_border.rbound;j++)
                    {
                        if(block_pos.pos_y+i<=AREA_ROW-1&&game_area[block_pos.pos_y+i][block_pos.pos_x+j]!=2)
                        {
                            game_area[block_pos.pos_y+i][block_pos.pos_x+j]=cur_block[i][j];
                        }
                    }
                }
         }
        ConvertStable(block_pos.pos_x,block_pos.pos_y);
        ResetBlock();
        break;
    default:
        break;
    }
    //处理消行，整个场景上面的行依次向下移动
    int i=AREA_ROW-1;
    int line_count=0;
    while(i>=1)
    {
        bool is_line_full=true;
        for(int j=0;j<AREA_COL;j++)
            if(game_area[i][j]==0)
            {
                is_line_full=false;
                i--;
                break;
            }
        if(is_line_full)
        {
            for(int k=i;k>=1;k--)
            {
                for(int j=0;j<AREA_COL;j++)
                {
                    game_area[k][j]=game_area[k-1][j];
                }
            }
            line_count++;//每次增加消行的行数
        }
    }

    score+=line_count*line_count*10;

    for(int j=0;j<AREA_COL;j++)
    {
        if(game_area[0][j]==2)
            GameOver();
    }
}
    bool Tetris::IsCollide(int x,int y,Direction dir)
    {
        int temp_block[4][4];
        block_cpy(temp_block,cur_block);

        Border temp_border;
        GetBorder(temp_block,temp_border);//重新计算行数

        switch(dir)
        {
        case UP:
            BlockRotate(temp_block);
            GetBorder(temp_block,temp_border);
            break;
        case DOWN:
            y+=1;
            break;
        case LEFT:
            x-=1;
            break;
        case RIGHT:
            x+=1;
            break;
        default:
            break;
        }

        for(int i=temp_border.ubound;i<=temp_border.dbound;i++)
        {
            for(int j=temp_border.lbound;j<=temp_border.rbound;j++)
            {
                if((game_area[y+i][x+j]==2&&temp_block[i][j]==1)||x+temp_border.lbound<0||x+temp_border.rbound>AREA_COL)
                {
                    return true;
                }

            }
        }
        return false;
    }
    void Tetris::keyPressEvent(QKeyEvent*event)
    {
        switch(event->key())
        {
        case Qt::Key_Up:
             BlockMove(UP);
             break;
        case Qt::Key_Down:
             BlockMove(DOWN);
             break;
        case Qt::Key_Left:
             BlockMove(LEFT);
             break;
        case Qt::Key_Right:
             BlockMove(RIGHT);
             break;
        case Qt::Key_Space:
             BlockMove(SPACE);
             break;
        default:
            break;
        }
    }

    void Tetris::timerEvent(QTimerEvent*event)
    {
        //方块下落
        if(event->timerId()==game_timer)
            BlockMove(DOWN);

        //刷新画面
        if(event->timerId()==paint_timer)
            update();
    }

    void Tetris::slotStartGame()
    {
        StartGame();
    }

    void Tetris::slotPauseGame()
    {
        PauseOrContinueGame();
    }
    void Tetris::slotStopGame()
    {
        GameOver();
    }
    void Tetris::slotHelp()
    {
        QMessageBox::about(this,tr("操作提示"),tr("左移：←键\n右移：→键\n旋转：↑键\n一键到底：空格键\n"));
    }
